package com.cirkana.viewer.data.route;

import java.io.FileInputStream;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import com.cirkana.data.DataException;
import com.cirkana.data.IDataCriteria;
import com.cirkana.data.IDataProvider;
import com.cirkana.data.IDataRecord;
import com.cirkana.data.route.IRouteDataResolver;
import com.cirkana.data.route.IRouteDetail;
import com.cirkana.data.route.IRouteDetailList;
import com.cirkana.data.route.gpx.IGpxRoute;
import com.cirkana.data.route.gpx.xml.GpxRouteXmlParser;
import com.cirkana.data.route.xml.RouteDetailListXmlParser;
import com.cirkana.viewer.data.criteria.DataCriteria;
import com.cirkana.viewer.data.route.gpx.GpxRoute;
import com.cirkana.viewer.data.route.gpx.GpxRouteMetadata;
import com.cirkana.viewer.data.route.gpx.GpxRouteTrack;
import com.cirkana.viewer.data.route.gpx.GpxRouteTrackPoint;
import com.cirkana.viewer.data.route.gpx.GpxRouteWayPoint;

public class RouteLocalDataResolver implements IRouteDataResolver {

	private static final NumberFormat ID_FORMATTER = new DecimalFormat("00000000");
	private static final String PREFIX_ROUTE_FILES = "R";
	private static final String ROUTES_PREFIX = ".gpx";

	private IDataProvider dataProvider;

	public RouteLocalDataResolver(IDataProvider dataProvider) {
		this.dataProvider = dataProvider;
	}

	public ArrayList<String> getLocalRoutes() {
		return dataProvider.getFilesList(ROUTES_PREFIX);
	}

	public FileInputStream openRoute(Integer id) throws DataException {
		return dataProvider.openFile(getFormattedRouteId(id));
	}

	public void saveRoute(Integer id, FileInputStream fileInputStream) throws DataException {
		dataProvider.saveFile(getFormattedRouteId(id), fileInputStream);
	}

	protected static String getFormattedRouteId(Integer id) {
		return PREFIX_ROUTE_FILES + ID_FORMATTER.format(id);
	}

	@Override
	public IRouteDetail newRouteDetail() {
		return new RouteDetail();
	}

	@Override
	public IRouteDetail newRouteDetail(String title, String description, String previewImage) {
		RouteDetail routeDetail = new RouteDetail();
		routeDetail.setTitle(title);
		routeDetail.setDescription(description);
		routeDetail.setPreviewImage(previewImage);
		return routeDetail;
	}

	public IRouteDetailList getRouteDetailList() throws DataException {
		ArrayList<IDataRecord> records = dataProvider.select(RouteDetail.tableDef);
		RouteDetailList list = new RouteDetailList();
		for (IDataRecord record : records)
			list.add((RouteDetail) record);
		return (IRouteDetailList) list;
	}

	public IRouteDetailList getRemoteRouteDetailList() throws DataException {
		RouteDetailListXmlParser xmlParser = new RouteDetailListXmlParser();
		try {
			return xmlParser.fromXml(requestGet("http://10.0.2.2:8080/cirkana.server.rest/rest/routes/list"), RouteDetailList.class, RouteDetail.class);
		} catch (Exception e) {
			throw new DataException(e);
		}
	}

	public IGpxRoute getRemoteGpxRoute(Integer id) throws DataException {
		GpxRouteXmlParser xmlParser = new GpxRouteXmlParser();
		try {
			return xmlParser.fromXml(requestGet("http://10.0.2.2:8080/cirkana.server.rest/rest/routes/" + id.toString()), GpxRoute.class,
					GpxRouteMetadata.class, GpxRouteWayPoint.class, GpxRouteTrack.class, GpxRouteTrackPoint.class);
		} catch (Exception e) {
			throw new DataException(e);
		}
	}

	private static InputStream requestGet(String urlString) throws DataException {
		HttpClient client = new DefaultHttpClient();
		HttpGet get = new HttpGet(urlString);
		try {
			HttpResponse response = client.execute(get);
			return response.getEntity().getContent();
		} catch (Exception e) {
			throw new DataException(e);
		}
	}

	public IRouteDetail getRouteDetail(Integer id) throws DataException {
		ArrayList<IDataCriteria> criterion = DataCriteria.getDataCriteriaList(DataCriteria.getIdDataCriteria(RouteDetail.COLUMN_ROUTE_ID, id));
		return (RouteDetail) this.dataProvider.select(RouteDetail.tableDef, criterion).get(0);
	}

	public IRouteDetail insertRouteDetail(IRouteDetail routeDetail) throws DataException {
		Integer id = this.dataProvider.insert(RouteDetail.tableDef, (IDataRecord) routeDetail);
		routeDetail.setId(id);
		return routeDetail;
	}

	public IRouteDetail updateRouteDetail(IRouteDetail routeDetail) throws DataException {
		this.dataProvider.update(RouteDetail.tableDef, (IDataRecord) routeDetail);
		return routeDetail;
	}

	public void deleteRouteDetail(IRouteDetail routeDetail) throws DataException {
		this.dataProvider.delete(RouteDetail.tableDef, (IDataRecord) routeDetail);
	}

}
